/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package com.dejax.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dejax.domain.BaseSysFunction;
import com.dejax.exception.BadRequestException;
import com.dejax.utils.*;
import lombok.RequiredArgsConstructor;
import com.dejax.repository.BaseSysFunctionRepository;
import com.dejax.service.BaseSysFunctionService;
import com.dejax.service.dto.BaseSysFunctionDto;
import com.dejax.service.dto.BaseSysFunctionQueryCriteria;
import com.dejax.service.mapstruct.BaseSysFunctionMapper;
import org.hibernate.annotations.Source;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.IdUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;


import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author Richer
* @date 2021-12-27
**/
@Service
@RequiredArgsConstructor
public class BaseSysFunctionServiceImpl implements BaseSysFunctionService {

    private final BaseSysFunctionRepository baseSysFunctionRepository;
    private final BaseSysFunctionMapper baseSysFunctionMapper;

    @PersistenceContext
    private EntityManager entityManager;


    private MapUtils mapUtils;


    @Override
    public Map<String,Object> queryAll(BaseSysFunctionQueryCriteria criteria, Pageable pageable){
        Page<BaseSysFunction> page = baseSysFunctionRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(baseSysFunctionMapper::toDto));
    }


    @Override
    public Page<BaseSysFunction>  queryAllData(BaseSysFunctionQueryCriteria criteria, Pageable pageable){
        StringBuffer dataBuffer = new StringBuffer(
                "SELECT funcinfo.*,appinfo.appname,pfuncinfo.funcname as pfuncname " +
                        "FROM base_sys_function funcinfo " +
                        "left join base_sys_appinfo appinfo on  appinfo.appid =funcinfo.appid " +
                        "left join base_sys_function pfuncinfo on  pfuncinfo.funcid =funcinfo.pfuncid " +
                        "WHERE 1 = 1 ");
        StringBuffer countBuffer = new StringBuffer(
                "SELECT count(*) " +
                        "FROM base_sys_function funcinfo " +
                        "left join base_sys_appinfo appinfo on  appinfo.appid =funcinfo.appid " +
                        "left join base_sys_function pfuncinfo on  pfuncinfo.funcid =funcinfo.pfuncid " +
                        "WHERE 1 = 1 ");

        StringBuffer paramBuffer = new StringBuffer();

        //功能名称
        if(criteria.getFuncname() != null){
            paramBuffer.append(" AND funcinfo.funcname like '%" + criteria.getFuncname() + "%'");
        }

        paramBuffer.append(" AND funcinfo.flag = 0");
        StringBuffer orderBuffer = new StringBuffer(
                "");

        String dataSql = (dataBuffer.append(paramBuffer).append(orderBuffer))
                .toString();
        String countSql = (countBuffer.append(paramBuffer)).toString();

        System.out.println("{} dataSql= " + dataSql);
        System.out.println("{} countSql= " + countSql);

        Query dataQuery = entityManager.createNativeQuery(dataSql.toString());
        Query countQuery = entityManager.createNativeQuery(countSql.toString());

        dataQuery.setFirstResult((int) pageable.getOffset());
        dataQuery.setMaxResults(pageable.getPageSize());
        dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        BigDecimal count = BigDecimal.valueOf(Integer.valueOf(String.valueOf(countQuery.getSingleResult())));
        Integer total = count.intValue();

        List content = total > pageable.getOffset() ? dataQuery
                .getResultList() : Collections.emptyList();
        return new PageImpl<BaseSysFunction>(content,pageable,total);
    }


    @Override
    public List<BaseSysFunctionDto> queryAll(BaseSysFunctionQueryCriteria criteria){
        return baseSysFunctionMapper.toDto(baseSysFunctionRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    public List<Map> getFuncTree(BaseSysFunctionQueryCriteria criteria){
        List<Map> list = getFuncTree(criteria.getAppid());
        return list;
    }


    private   Map<String, Object> object2Map(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }


    //获取 functionc 树结构
    private List<Map> getFuncTree(String appid){

        List<BaseSysFunction> treeList = baseSysFunctionRepository.getTreeData(appid);

        List<Map<String,Object>> mapList = new ArrayList<>();

        for (int i = 0; i < treeList.size(); i++) {
            System.out.println(treeList.get(i));
            System.out.println(1111);
            Map<String, Object> map = object2Map(treeList.get(i));
            mapList.add(map);
        }

        System.out.println("mapList");
        System.out.println(mapList);

        List<Map> result = this.buildFuncTree(mapList,"null");

        System.out.println(result);

        return result;

    }

    private List<Map> buildFuncTree(List<Map<String,Object>> tempList,String pid){
        List<Map> newList = new ArrayList<>();
        for (int i = 0; i < tempList.size(); i++) {
            Map<String,Object> funcInfoOne = tempList.get(i);

            if(String.valueOf(funcInfoOne.getOrDefault("pfuncid","null")).equals(pid)){
                funcInfoOne.put("children",buildFuncTree(tempList, String.valueOf(funcInfoOne.get("funcid"))));
                funcInfoOne.put("value",funcInfoOne.get("funcid"));
                funcInfoOne.put("label",funcInfoOne.get("funcname"));
                newList.add(funcInfoOne);
            }

        }

        return newList;
    }

    @Override
    @Transactional
    public BaseSysFunctionDto findById(String funcid) {
        BaseSysFunction baseSysFunction = baseSysFunctionRepository.findById(funcid).orElseGet(BaseSysFunction::new);
        ValidationUtil.isNull(baseSysFunction.getFuncid(),"BaseSysFunction","funcid",funcid);
        return baseSysFunctionMapper.toDto(baseSysFunction);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseSysFunctionDto create(BaseSysFunction resources) {
        resources.setFuncid(IdUtil.simpleUUID());
        resources.setFlag(0);
        BaseSysFunction baseSysFunction = baseSysFunctionRepository.findOneByAppidFuncname(resources.getAppid(),resources.getFuncname());
        if(baseSysFunction != null){
            throw new BadRequestException(BAD_REQUEST, "该功能名称已存在");
        }
        return baseSysFunctionMapper.toDto(baseSysFunctionRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(BaseSysFunction resources) {
        BaseSysFunction baseSysFunction = baseSysFunctionRepository.findById(resources.getFuncid()).orElseGet(BaseSysFunction::new);
        ValidationUtil.isNull( baseSysFunction.getFuncid(),"BaseSysFunction","id",resources.getFuncid());
        baseSysFunction.copy(resources);
        baseSysFunctionRepository.save(baseSysFunction);
    }

    @Override
    public void deleteAll(String[] ids) {
        BaseSysFunction updatesource = new BaseSysFunction();
        for (String funcid : ids) {
            updatesource.setFuncid(funcid);
            updatesource.setFlag(1);
            this.update(updatesource);
        }
    }

    @Override
    public void download(List<BaseSysFunctionDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (BaseSysFunctionDto baseSysFunction : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("功能名称", baseSysFunction.getFuncname());
            map.put("父功能id", baseSysFunction.getPfuncid());
            map.put("功能描述", baseSysFunction.getFuncdesc());
            map.put("排序序号", baseSysFunction.getOrderno());
            map.put("节点层级", baseSysFunction.getFunclevel());
            map.put("节点路径", baseSysFunction.getFuncpath());
            map.put("应用系统id", baseSysFunction.getAppid());
            map.put(" flag",  baseSysFunction.getFlag());
            map.put(" notes",  baseSysFunction.getNotes());
            map.put(" reguser",  baseSysFunction.getReguser());
            map.put(" regtime",  baseSysFunction.getRegtime());
            map.put(" moduser",  baseSysFunction.getModuser());
            map.put(" modtime",  baseSysFunction.getModtime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}